package com.dingwen.rabpro.service.impl;

import com.dingwen.rabpro.constant.RabbitConstant;
import com.dingwen.rabpro.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * order service impl
 * <p>
 * topic 模式
 * </p>
 * <ol>
 *     <li>* 至多一个</li>
 *     <li># 至少一个</li>
 * </ol>
 * <p>消息可靠投递</p>
 * <pre>
 *     1. 消息投递到指定交换机时触发回调  {@code  rabbitTemplate.setConfirmCallback}
 *      1.1 yml配置{@yml spring.rabbimq.publisher-confirm-type: correlated}
 *      1.2 correlated: 消息投递成功，调用
 *      1.3 simple: 兼备correlated的功能，另执行wait等待broker的反馈再进行操作
 *      1.4 none: 关闭此项功能
 *     2. 消息投递到队列之后，之前到操作发生错误进行回调
 *      2.1 yml 配置publisher-returns: true
 *      2.2 开启broker给生产着反馈消息{@code rabbitTemplate.setMandatory(Boolean.TRUE);}
 *      2.3 rabbitTemplate.setReturnsCallback
 *
 * </pre>
 *
 * @author dingwen
 * 2021.06.17 11:11
 */
@Service
@Slf4j
@SuppressWarnings("ALL")
public class OrderServiceImpl implements OrderService {

    @Resource
    private RabbitTemplate rabbitTemplate;


    @Override
    public void placeOrder() {

        //placeOrderForSetMessageTTL();

        // fanout
        //  rabbitTemplate.convertAndSend(RabbitConstant.FANOUT_EXCHANGE_NAME, null, UUID.randomUUID().toString());
        // direct
        // 开启消息投递到指定交换机的回调
//       rabbitTemplate.setConfirmCallback(getConfirmCallback());


        // 开启消息投递return回调
//        enableReturnsCallback();


        rabbitTemplate.convertAndSend(RabbitConstant.FANOUT_EXCHANGE_NAME, null, UUID.randomUUID().toString());
    }

    /**
     * 下单，设置消息过期时间发送消息 <br>
     * <p>
     * 当同时设置了单条消息的过期时间和整个队列的消息过期时间则以时间短的为准，注意当消息到达队列顶端是才会进行判断消息是否过期从而进行删除
     * </p>
     */
    private void placeOrderForSetMessageTtl() {
        // 测试消息过期时间
        MessagePostProcessor messagePostProcessor = (message) -> {
            MessageProperties messageProperties = message.getMessageProperties();
            messageProperties.setContentEncoding("UTF-8");
            messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
            // 过期时间 5000 毫秒
            messageProperties.setExpiration("5000");
            return message;
        };
        // fanout
        rabbitTemplate.convertAndSend(RabbitConstant.FANOUT_EXCHANGE_NAME, null, UUID.randomUUID().toString(), messagePostProcessor);
    }


    /**
     * 确保消息发送确认回调 <br>
     * <p>
     * 当消息发送到broker分发到指定交换机之后进行此方法到回调
     * </p>
     */
    private RabbitTemplate.ConfirmCallback getConfirmCallback() {
        return (correlationData, isSuccess, errMessage) -> {
            log.info("消息已经发送到指定交换机");
        };
    }

    /**
     * 开启ReturnsCallback回调 <br>
     * <p>
     *     消息投递到队列之前出现错误执行回调方法
     * </p>
     */
    private void enableReturnsCallback() {
        rabbitTemplate.setMandatory(Boolean.TRUE);
        RabbitTemplate.ReturnsCallback returnsCallback = returnedMessage -> {

        };
    }


    /**
     *记忆线程休眠Api
     */
    private void rememberSleepApi(){
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
